home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
IRIX Installation Tools & Overlays 2002 May
/
SGI IRIX Installation Tools & Overlays 2002 May - Disc 3.iso
/
relnotes
/
dmedia_dev
/
ch08.z
/
ch08
Wrap
Text File
|
2002-04-11
|
95KB
|
1,651 lines
- 1 -
9. _A_u_d_i_o__F_i_l_e__L_i_b_r_a_r_y
This chapter lists information about the Audio File Library
programming interface included in the the IRIS Digital Media
Development Environment. It includes changes, additions,
and bug fixes since the last release, and known problems,
workarounds, and caveats.
The Audio File Library consists of approximately 100 C
routines that allow application programs to read/write audio
sample data and auxiliary header information to/from a
number of standard audio file formats. The library requires
no special audio hardware at runtime, and is useful for
sound file import/export/conversion operations as well as
real-time recording/playback.
The Audio File Library API allows you to access audio
samples and nonaudio information from audio files using a
common set of routines. The API includes functions for
reading/writing various types of data including author,
copyright, name, and annotation strings; sample frame marker
locations; sample configuration parameters and loop points;
MIDI exclusive data; and application-defined data.
The Audio File Library implements transparent sample data
format conversion and compression/decompression for many
different audio file formats. The following compression
algorithms are currently supported:
+o MPEG-1 Layers I and II
+o Aware Inc.'s, proprietary MultiRate algorithm
+o ITU G.711 mu-law and A-law
+o ITU G.722 ADPCM
+o ITU G.726 ADPCM
+o ITU G.728 ADPCM
+o GSM 06.10
+o IMA DVI ADPCM
+o US Federal Standard 1016 CELP
Transparent format conversion and compression/decompression
means that application programs can process all audio files
as uncompressed data in any format that the application
desires. There is no need to write special code for
- 2 -
handling different sample formats or types of compressed
data. Compressed and decompressed files look the same to
applications as long as the compression format is one of the
supported types listed above.
Note: The Aware MultiRate codec cannot be activated by an
application without a FlexLM node-locked license,
available from SGI.
See the online man page _a_w_a_r_e(_5) for an overview of
the Aware compression technology available to
developers and end users. The online man page
_a_f_I_n_i_t_C_o_m_p_r_e_s_s_i_o_n(3dm) describes the Audio File
Library interface to reading/writing audio files that
contain MultiRate or other types of compressed data.
The Audio File Library API is intended to be general enough
to allow support for additional digital audio file formats
and compression schemes in the future. Applications that
developed using the current version of the library will be
able to read these additional file and data formats as new
versions of the Audio File Library are released, without
need for re-linking.
Applications linked with the 6.X Audio File Library no
longer need to be linked with any other library. All that
is needed on the link line is:
----llllaaaauuuuddddiiiiooooffffiiiilllleeee
The exception to this are cases where an application makes
calls to the Digital Media Library error retrieval routine
_d_m_G_e_t_E_r_r_o_r(3dm) (see details below).
The _I_R_I_S _D_i_g_i_t_a_l _M_e_d_i_a _P_r_o_g_r_a_m_m_i_n_g _G_u_i_d_e contains an
introduction to programming with the Audio File Library,
along with a description of each of its functions.
The on-line man page _a_f_I_n_t_r_o(3dm) provides a brief overview
of the library and a list of the available procedure calls.
There is a small set of Audio Utility routines contained
within libdmedia.so which are oftne used in conjunction with
the Audio File Library. This set includes the function
_A_U_c_h_e_c_k_l_i_c_e_n_s_e(3dm), which allows an application to query
license availability for the Aware, Inc.
compressor/decompressor software on the current host, and
several functions that implement a generalized parameter-
value list object for use with the Audio File Library
routines _a_f_I_n_i_t_C_o_m_p_r_e_s_s_i_o_n_P_a_r_a_m_s(3dm) and
_a_f_G_e_t_C_o_m_p_r_e_s_s_i_o_n_P_a_r_a_m_s(3dm). See the man page _A_U_p_v_n_e_w(3dm)
- 3 -
for a description of these routines.
See the source code _a_i_f_c_c_o_n_v_e_r_t._c in the directory
/_u_s_r/_s_h_a_r_e/_s_r_c/_d_m_e_d_i_a/_s_o_u_n_d_c_o_m_m_a_n_d_s for Audio Utility
programming example.
9.1 _E_x_a_m_p_l_e__P_r_o_g_r_a_m_s__i_n__/_u_s_r_/_s_h_a_r_e_/_s_r_c_/_d_m_e_d_i_a_/_a_u_d_i_o
The subsystems _d_m_e_d_i_a__d_e_v._s_r_c._t_o_o_l_s and
_d_m_e_d_i_a__d_e_v._s_r_c._e_x_a_m_p_l_e_s contain several source code examples
for programming with the Audio File Library. Executable
versions of some of these programs are included as standard
system utilities which can be installed from the
_d_m_e_d_i_a__e_o_e._s_w._t_o_o_l_s subsystem included with the IRIX 6.5 O/S
release. However, as noted in the Changes section below,
most of these programs are now obsolete and are only
provided as example code, and their functionality has been
taken over by other programs.
_s_f_p_l_a_y(1) and _s_f_r_e_c_o_r_d(1) are command-line programs for
playing and recording files in a variety of file formats and
compression types. The programs are built on top of the IRIS
Audio Library and the Audio File Library. The source code
for these programs is available in
/_u_s_r/_s_h_a_r_e/_s_r_c/_d_m_e_d_i_a/_s_o_u_n_d_c_o_m_m_a_n_d_s/{_p_l_a_y._c,_s_f_r_e_c_o_r_d._c}
_a_i_f_c_i_n_f_o(1) is a command-line program that parses an
AIFF/AIFF-C input file and prints a description of the data
in the file, including characteristics of the audio sample
data, and a summary of the nonaudio data (strings, loop
points, and so on) found in the various file header fields.
The source code is installed in
/_u_s_r/_s_h_a_r_e/_s_r_c/_d_m_e_d_i_a/_s_o_u_n_d_c_o_m_m_a_n_d_s/_a_i_f_c_i_n_f_o._c.
_a_i_f_f_2_a_i_f_c(1), _a_i_f_c_2_a_i_f_f(1), _a_i_f_c_c_o_m_p_r_e_s_s(1), and
_a_i_f_c_d_e_c_o_m_p_r_e_s_s(1) are old command-line utility programs for
converting between AIFF-C and AIFF files, or for converting
AIFF-C files between compressed and uncompressed data
formats. These utilities are all obsolete, as indicated
below. The source for the program is the file
/_u_s_r/_s_h_a_r_e/_s_r_c/_d_m_e_d_i_a/_s_o_u_n_d_c_o_m_m_a_n_d_s/_a_i_f_c_c_o_n_v_e_r_t._c.
9.2 _C_h_a_n_g_e_s__a_n_d__A_d_d_i_t_i_o_n_s__S_i_n_c_e__6_._4
This section lists changes/additions to the Audio File
Library and accompanying example source code since its last
release.
+o One new compression type has been added: Federal
Standard 1016 CELP. IMA4:1 compression is now
- 4 -
available for both WAVE and AIFF-C file formats.
+o AIFF-C files now support 32-bit single precision and
64-bit double precision floating point data formats.
Note that though this conforms to Apple, Inc.'s
specification, it is likely that very few non-SGI
applications will be equipped to read these files.
+o AIFF-C files with audio compression now precisely
conform to Apple, Inc.'s specification. This will
allow much greater portability for such files.
+o The aaaaffffQQQQuuuueeeerrrryyyy(3dm) routine has been expanded to include
queries regarding compression parameters. See the man
page for this routine for further information.
9.3 _C_h_a_n_g_e_s__a_n_d__A_d_d_i_t_i_o_n_s__S_i_n_c_e__b_e_t_w_e_e_n__A_F__v_e_r_s_i_o_n_s__1__a_n_d__2
This section lists changes/additions to the Audio File
Library and accompanying example source code between the old
(5.3) and the new version. This information remains
available for developers who are upgrading directly from a
5.X release to 6.5.
+o The version 2 AF allows transparent conversion of the
audio data in a file's track into an uncompressed
format of the application's choice. This new format is
known as the _v_i_r_t_u_a_l format of the data. The
application need not concern itself with the data
format in the file; it can specify the format in which
it would like to receive the data. This also works in
the other direction: A buffer of data in any
uncompressed format may be written out to a file
containing data in any other format (assuming the audio
file type specified supports that format). Read the
_a_f_I_n_t_r_o(3dm) man page for a detailed explanation of
this procedure.
+o The following list of audio utility programs has been
made obsolete by the new _d_m_c_o_n_v_e_r_t(3dm) and/or
_d_m_i_n_f_o(3dm) utilities:
aaaaiiiiffffffff2222aaaaiiiiffffcccc,,,, aaaaiiiiffffcccc2222aaaaiiiiffffffff,,,, aaaaiiiiffffccccccccoooommmmpppprrrreeeessssssss,,,, aaaaiiiiffffccccddddeeeeccccoooommmmpppprrrreeeessssssss,,,, aaaaiiiiffffcccciiiinnnnffffoooo
For backwards compatibility, these utilities still
exist as symbolic links to the new programs. SGI
offers no guarantee that this will be continued in
future releases.
+o The version 2 AF has adopted a new standard for the
naming of publically available routines. All Audio
- 5 -
File Library routines now consist of the prefix "af"
(in small case letters) followed by any number of words
describing the function, with the first letter of each
word capitalized. To allow existing code to run when
linked against the new library, two forms of
backwards-compatibility are built into the library:
+o The public header file <dmedia/audiofile.h>
contains a set of #define's which will cause the
preprocessor to rename each occurrence of the old
routine names in existing code when and if it is
recompiled from source.
+o For code which is not recompiled but which chooses
to link against the 2.0 version of the library
(see the section "How Does This DSO Magic Work?"
below), a set of wrapper functions are contained
within the library to allow the old routine symbol
names to be resolved properly. For ease in
debugging and maximum efficiency, it is
recommended that programs be recompiled to allow
the redefines to happen, or better yet, rename the
function calls using the new scheme.
9.4 _B_u_g__F_i_x_e_s
This section describes fixes made to the code since the 6.4
release.
+o
+o
9.5 _K_n_o_w_n__P_r_o_b_l_e_m_s__a_n_d__W_o_r_k_a_r_o_u_n_d_s
This section lists problems in the new Audio File Library
software and ways to work around them.
+o AIFF-C comment chunks: the Audio File Library API does
not yet include routines for reading/writing comment
chunk data in AIFF-C files. The library routine
_a_f_O_p_e_n_F_i_l_e(3dm) allows you to open an AIFF-C file that
contains a comment chunk, but there is no way to access
the comment chunk fields through library routines.
+o Apple Computer proprietary compression algorithms:
several compression algorithms described in the AIFF-C
specification (ACE2, ACE8, MAC3, MAC6) are Apple
proprietary and cannot be decoded on IRIS workstations.
To avoid problems with proprietary or unsupported
compression algorithms, convert AIFF-C files so that
- 6 -
they contain uncompressed data before attempting to
transfer them between an IRIS workstation and another
audio workstation platform.
+o Aware MultiRate codec: An application is only allowed
to have one AFfilehandle open at a time which uses the
Aware MultiRate or Lossless compressor or decompressor.
This applies to the application's entire process share
group. In addition, the MultiRate algorithm has a
large number of memory leaks. Avoid opening large
numbers of MultiRate-compressed files in any single
application. Due to the limited support which SGI
supplies for this codec, it is unlikely that this will
be fixed in the foreseeable future.
Note: These bugs does not apply to the SGI MPEG1
implementation.
9.6 _D_o_c_u_m_e_n_t_a_t_i_o_n__E_r_r_o_r_s
This section lists errors in the Audio File Library
documentation.
+o No known errors at this time.
9.7 _A_u_d_i_o__F_i_l_e__L_i_b_r_a_r_y_:__D_e_v_e_l_o_p_e_r__N_o_t_e_s
An important warning to developers about using the IRIX 6.X
Audio File Library (version 2). This information continues
to be provided as a reference for porting old IRIX 5.X
applications to later OS releases. The 2.0 version of the
Audio File Library is referred to as the "new" version.
9.7.1 _I_n_t_r_o_d_u_c_t_i_o_n It has come to our attention that some
applications which use the Audio File Library are making
untrue assumptions about the library. These assumptions,
though in conflict with the practice laid out by our
documentation, happened coincidentally not to cause any
errors with versions of the library shipped with IRIX 5.3
and earlier. But it is entirely possible that some of these
mis-coded applications will fail when run with this new
release of the library.
As the Audio File Library is a Dynamic Shared Object (DSO),
this is a matter of some concern to developers, as end-users
may upgrade OS releases and get a new DSO which breaks their
applications without the applications' developer having had
a chance to re-release.
- 7 -
The library released with IRIX 6.X was a superset of the
previously-released library. New functionality has been
added and will continue to be added, but all previously-
existing functions are still present.
This section is provided to warn developers of problems
which may be experienced with the new releases due to
incorrect assumptions made in application code.
The first problem involves assumptions about the kinds of
files the library will be able to open. The second and
third problems have to do with using the Audio Library in
multi-threaded applications. The fourth problem involves
the use of an AFfilehandle's file descriptor while the
filehandle is alive. Then we follow with a warning about
the correlation between AF calls and actual UNIX operations
on files (such as read(), write(), and lseek() system
calls).
9.7.2 _U_s_e__o_f__t_h_e__O_l_d__V_e_r_s_i_o_n__o_f__t_h_e__A_u_d_i_o__F_i_l_e__L_i_b_r_a_r_y
Because the confusion described above seems to be fairly
widespread, and because some of this confusion may have
stemmed from insufficient emphasis of these points in SGI's
documentation, the new library has been modified via the SGI
DSO versioning system so that programs built prior to the
6.X release will still bind to a copy of the old library.
This means that old AF programs will not be able to get the
feature and performance improvements of the new Audio File
Library without relinking. But this will also decrease the
chances that bugs in developers' application code such as
the ones described below will be exposed, until the
developer has a chance to repair their application, relink
to bind to the new DSO, and ship a new version to their
customers.
We did this version change as a one-time aid for developers.
We do not intend to create new DSO versions for each new
audio file library upgrade.
We give no guarantees that the old version of libaudiofile
will be maintained in the same manner as the new version, or
in any way whatsoever. But we can guarantee that we will
not intentionally make changes to it which would cause
applications with the below pitfalls to fail. Please note
however that some of the problems below could happen at any
time, whether libaudiofile changes or not. Some could
surface to users as a result of a change of any software on
the system or even a change of system hardware. So just
because we are keeping this older libaudiofile.so does not
mean developers have any guarantee whatsoever that their
programs will continue to execute fine. All developers
- 8 -
should check their software for these problems and remove
them as soon as possible.
9.7.3 _H_o_w__D_o_e_s__T_h_i_s__D_S_O__M_a_g_i_c__W_o_r_k_? The version of the
Audio File library which shipped with IRIX 5.1, 5.2, and 5.3
was stamped with the interface version "sgi1.0". This can
be seen by looking at the MIPS_IVERSION entry of the DSO
using "elfdump -L <library>". Similarly, the IRIX 6.X
version of the Audio File Library is stamped "sgi2.0". When
a program (specifically, a NON-ABI executable) is linked
under IRIX 5.X and the DSO is specified on the command line
using an argument such as -laudiofile, ld looks at the
currently available DSOs, picks the one called
libaudiofile.so, and places that DSO's name and its
interface version stamp in the executable's liblist, which
can be seen with "elfdump -Dl <executable>".
Then at some later time, the executable is run. This could
be before or after a new version of the Audio File Library
is installed. The system (specifically, rld) must then find
a libaudiofile DSO to use which has a major version of 1
(the major version is the number before the decimal point in
the interface version stamp "sgi1.0"). If no new version of
the Audio File Library has been installed, the system will
immediately find libaudiofile.so, discover that it has an
interface version of "sgi1.0", and use it. If a new version
of the Audio File Library has been installed as
libaudiofile.so, the system will find this DSO first, it
will look and see that the version number is "sgi2.0", and
it will reject this file. It will then look for another DSO
called libaudiofile.so.1, since it wants to find major
version 1 of this DSO. Since we have now installed the old
DSO libaudiofile.so.1, the system will find this DSO and use
it.
In order for an old program to bind to the new DSO, the
programmer must relink it on a system which has version 2 of
the DSO. This way, "sgi2.0" will be stored in the entry of
program's liblist for libaudiofile.so. An alternate way to
make an AF program bind to the new DSO instead of the old
(1.0) DSO is to set the environment variable _RLD_ARGS to
'-ignore_version libaudiofile.so', but this will affect all
AF programs executed with this environment variable set.
DSOs and DSO versioning are covered in dso(5), ld(1),
rld(1), and other man pages. dso(5) contains references for
more information.
9.7.4 _P_R_O_B_L_E_M__1 Assumption that AF only reads and writes a
certain set of file and data formats.
- 9 -
The AF is a library which now supports many file formats
(besides AIFF and AIFF-C) and data formats (besides 2's
complement integer and compressed data formats).
This is why we always stated in the old man pages that
certain formats were the "currently supported" formats (man
afIntro(3dm)), or that certain data formats or chunk
configurations were possible "from AIFF files" rather than
"from files".
The Audio File Library has the following behaviors which may
break applications making the above assumption when a new
library is released:
int filefmt = afIdentifyFD(fd);
int filefmt = afGetFileFormat(handle, &version);
Applications use afIdentifyFD for two reasons: seeing
whether the AF recognizes an audio file, and seeing
specifically which format the audio file has. The user uses
afGetFileFormat for the latter purpose (as well as getting
the format version, if applicable). This section covers the
pitfalls of each use separately:
CHECK FOR RECOGNITION:
The filefmt returned could very well be something other than
AF_FILE_AIFF or AF_FILE_AIFFC. This version of the library,
for example, supports six formats. The application should
make no assumptions about what tokens could be returned.
Therefore code such as:
iiiiffff ((((ffffiiiilllleeeeffffmmmmtttt !!!!==== AAAAFFFF____FFFFIIIILLLLEEEE____AAAAIIIIFFFFFFFF &&&&&&&&
ffffiiiilllleeeeffffmmmmtttt !!!!==== AAAAFFFF____FFFFIIIILLLLEEEE____AAAAIIIIFFFFFFFFCCCC))))
{{{{
pppprrrriiiinnnnttttffff((((""""tttthhhhiiiissss ffffiiiilllleeee iiiissss nnnnooootttt ssssuuuuppppppppoooorrrrtttteeeedddd bbbbyyyy tttthhhheeee AAAAFFFF lllliiiibbbbrrrraaaarrrryyyy!!!!\\\\nnnn""""))));;;;
eeeexxxxiiiitttt((((0000))));;;;
}}}}
is incorrect because it is quite reasonable for the AF to
return a value other than one found in the include file.
Instead, the code should test whether the AF did not
recognize the file format rather than testing for what it
thinks is all possible recognized formats. Here's one
example:
iiiiffff ((((ffffiiiilllleeeeffffmmmmtttt ======== AAAAFFFF____FFFFIIIILLLLEEEE____UUUUNNNNSSSSUUUUPPPPPPPPOOOORRRRTTTTEEEEDDDD ||||||||
ffffiiiilllleeeeffffmmmmtttt ======== AAAAFFFF____FFFFIIIILLLLEEEE____UUUUNNNNKKKKNNNNOOOOWWWWNNNN))))
- 10 -
{{{{
pppprrrriiiinnnnttttffff((((""""tttthhhhiiiissss ffffiiiilllleeee iiiissss nnnnooootttt ssssuuuuppppppppoooorrrrtttteeeedddd bbbbyyyy tttthhhheeee AAAAFFFF lllliiiibbbbrrrraaaarrrryyyy!!!!\\\\nnnn""""))));;;;
eeeexxxxiiiitttt((((0000))));;;;
}}}}
The difference here is that the code acknowledges that there
are file formats which could be returned which the coder did
not know about at the time of coding.
GETTING THE FORMAT ITSELF
What about programs which actually care what the file format
of a file they are opening is? Note that this should be
rare, because in the AF, the data format of a file's track
is queried and manipulated totally independently of the
file's file format. So only programs which actually have to
make distinctions like "AIFF vs. AIFF-C" need use
afGetFileFormat or afIdentifyFD for this purpose.
The caveat here, just as stated above, is that the library
could easily return something other than one of the
AF_FILE_... tokens found in /usr/include/audiofile.h at the
time of compilation. This is because the Audio File Library
is a dynamic shared object (DSO), and thus when newer
versions of the audio file library supporting new file
formats are released with new OS's, programs linked at an
earlier time will automatically pick up the new library, and
thus could see the tokens corresponding to the newly
supported formats.
Before you start worrying about how to handle this
situation, make sure you have to worry about the file format
at all:
Many applications which check the filefmt should really be
checking the sampfmt and other track parameters of the
file's track. For example, there is no reason why a program
which simply reads the audio data out of a 16-bit
AF_SAMPFMT_TWOSCOMP AIFF file would not be able to function
just as well reading that kind of data out of a NeXT/Sun
file, as long as it did not intend to read AIFF-specific
chunks out of it as well (certain miscs and insts, for
example). Such a program has no need to call afIdentifyFD
or afGetFileFormat to get the file format.
But for those applications that do care about the file
format, code such as this:
sssswwwwiiiittttcccchhhh ((((aaaaffffIIIIddddeeeennnnttttiiiiffffyyyyFFFFDDDD((((ffffdddd))))))))
{{{{
- 11 -
ccccaaaasssseeee AAAAFFFF____FFFFIIIILLLLEEEE____AAAAIIIIFFFFFFFF::::
pppprrrriiiinnnnttttffff((((""""TTTThhhhiiiissss iiiissss aaaannnn AAAAIIIIFFFFFFFF ffffiiiilllleeee....\\\\nnnn""""))));;;;
ddddoooo____aaaaiiiiffffffff____tttthhhhiiiinnnngggg(((())));;;;
bbbbrrrreeeeaaaakkkk;;;;
ccccaaaasssseeee AAAAFFFF____FFFFIIIILLLLEEEE____AAAAIIIIFFFFFFFFCCCC::::
pppprrrriiiinnnnttttffff((((""""TTTThhhhiiiissss iiiissss aaaannnn AAAAIIIIFFFFFFFF----CCCC ffffiiiilllleeee....\\\\nnnn""""))));;;;
ddddoooo____aaaaiiiiffffffffcccc____tttthhhhiiiinnnngggg(((())));;;;
bbbbrrrreeeeaaaakkkk;;;;
ccccaaaasssseeee AAAAFFFF____FFFFIIIILLLLEEEE____UUUUNNNNKKKKNNNNOOOOWWWWNNNN::::
ccccaaaasssseeee AAAAFFFF____FFFFIIIILLLLEEEE____UUUUNNNNSSSSUUUUPPPPPPPPOOOORRRRTTTTEEEEDDDD::::
pppprrrriiiinnnnttttffff((((""""tttthhhhiiiissss ffffiiiilllleeee iiiissss nnnnooootttt ssssuuuuppppppppoooorrrrtttteeeedddd bbbbyyyy AAAAFFFF lllliiiibbbbrrrraaaarrrryyyy!!!!!!!!\\\\nnnn""""))));;;;
eeeexxxxiiiitttt((((0000))));;;;
ddddeeeeffffaaaauuuulllltttt::::
////**** aaaassssssssuuuummmmeeee tttthhhheeeerrrreeee hhhhaaaassss bbbbeeeeeeeennnn ssssoooommmmeeee pppprrrrooooggggrrrraaaammmmmmmmaaaattttiiiicccc eeeerrrrrrrroooorrrr ****////
pppprrrriiiinnnnttttffff((((""""bbbbaaaadddd rrrreeeettttuuuurrrrnnnn vvvvaaaalllluuuueeee ffffrrrroooommmm AAAAFFFF lllliiiibbbbrrrraaaarrrryyyy!!!!!!!!\\\\nnnn""""))));;;;
aaaasssssssseeeerrrrtttt((((0000))));;;;
}}}}
should be changed to code that at least does this:
sssswwwwiiiittttcccchhhh ((((aaaaffffIIIIddddeeeennnnttttiiiiffffyyyyFFFFDDDD((((ffffdddd))))))))
{{{{
ccccaaaasssseeee AAAAFFFF____FFFFIIIILLLLEEEE____AAAAIIIIFFFFFFFF::::
pppprrrriiiinnnnttttffff((((""""TTTThhhhiiiissss iiiissss aaaannnn AAAAIIIIFFFFFFFF ffffiiiilllleeee....\\\\nnnn""""))));;;;
ddddoooo____aaaaiiiiffffffff____tttthhhhiiiinnnngggg(((())));;;;
bbbbrrrreeeeaaaakkkk;;;;
ccccaaaasssseeee AAAAFFFF____FFFFIIIILLLLEEEE____AAAAIIIIFFFFFFFFCCCC::::
pppprrrriiiinnnnttttffff((((""""TTTThhhhiiiissss iiiissss aaaannnn AAAAIIIIFFFFFFFF----CCCC ffffiiiilllleeee....\\\\nnnn""""))));;;;
ddddoooo____aaaaiiiiffffffffcccc____tttthhhhiiiinnnngggg(((())));;;;
bbbbrrrreeeeaaaakkkk;;;;
ccccaaaasssseeee AAAAFFFF____FFFFIIIILLLLEEEE____UUUUNNNNKKKKNNNNOOOOWWWWNNNN::::
ccccaaaasssseeee AAAAFFFF____FFFFIIIILLLLEEEE____UUUUNNNNSSSSUUUUPPPPPPPPOOOORRRRTTTTEEEEDDDD::::
pppprrrriiiinnnnttttffff((((""""tttthhhhiiiissss ffffiiiilllleeee iiiissss nnnnooootttt ssssuuuuppppppppoooorrrrtttteeeedddd bbbbyyyy AAAAFFFF lllliiiibbbbrrrraaaarrrryyyy!!!!!!!!\\\\nnnn""""))));;;;
eeeexxxxiiiitttt((((0000))));;;;
ddddeeeeffffaaaauuuulllltttt::::
pppprrrriiiinnnnttttffff((((""""tttthhhhiiiissss pppprrrrooooggggrrrraaaammmm ccccaaaannnnnnnnooootttt hhhhaaaannnnddddlllleeee tttthhhhiiiissss ffffiiiilllleeee ffffoooorrrrmmmmaaaatttt!!!!\\\\nnnn""""))));;;;
eeeexxxxiiiitttt((((0000))));;;;
}}}}
Applications can now query the AF at runtime in order to
determine which file formats are supported by the version of
the AF to which the running program has bound. In addition
to querying the token that is used to refer to each file
format, users can query for the textual name and other
characteristics of each format. See the _a_f_Q_u_e_r_y(3dm) man
page for a complete description of this technique.
For many applications, getting the textual name of the file
format is the entire reason they wanted to call afIdentifyFD
or afGetFileFormat in the first place, and so such
- 12 -
applications can be now written so that they instantly and
automatically understand every file format which the
currently-bound Audio File Library understands, as in:
iiiinnnntttt ffffiiiilllleeeeffffmmmmtttt ==== aaaaffffIIIIddddeeeennnnttttiiiiffffyyyyFFFFDDDD((((ffffdddd))));;;;
cccchhhhaaaarrrr ****nnnnaaaammmmeeee ==== ((((cccchhhhaaaarrrr ****)))) aaaaffffQQQQuuuueeeerrrryyyyPPPPooooiiiinnnntttteeeerrrr((((AAAAFFFF____QQQQUUUUEEEERRRRYYYYTTTTYYYYPPPPEEEE____FFFFIIIILLLLEEEEFFFFMMMMTTTT,,,,
AAAAFFFF____QQQQUUUUEEEERRRRYYYY____NNNNAAAAMMMMEEEE,,,, ffffiiiilllleeeeffffmmmmtttt,,,, 0000,,,, 0000))));;;;
pppprrrriiiinnnnttttffff((((""""TTTThhhhiiiissss iiiissss ffffiiiilllleeee hhhhaaaassss tttthhhheeee %%%%ssss ffffiiiilllleeee ffffoooorrrrmmmmaaaatttt....\\\\nnnn"""",,,, nnnnaaaammmmeeee))));;;;
So what guarantees does the developer have?
The library will never support fewer formats. If a user
uses an AF_FILE_ token that we ship with a software release,
that token and its associated file format will never become
unsupported, although it may become obsolete (and perhaps
new features will not be available for it). So for example,
the library will never stop supporting AF_FILE_AIFF or
AF_FILE_AIFFC.
The library will always provide the query mechanism. We
have made every effort to make the query mechanism versatile
enough that user programs can make intelligent decisions
about how to deal with and report info on audio files of
different file formats.
afGetSampleFormat(AFfilehandle, int track, int *sampfmt, int
*sampwidth);
Here is the single most likely offender that could be found
in developer's programs. Because the new AF supports
transparent data format conversion, you may not have to use
this routine at all, and many of the below-mentioned issues
will go away.
As the man page says, AIFF and AIFF-C files only support
AF_SAMPFMT_TWOSCOMP files. However, as the library now
support other file formats, it is quite likely the library
may return some other sample format. So code that says:
AAAAFFFFffffiiiilllleeeehhhhaaaannnnddddlllleeee hhhh ==== aaaaffffOOOOppppeeeennnnFFFFiiiilllleeee((((................))));;;;
iiiiffff ((((!!!!hhhh)))) rrrreeeettttuuuurrrrnnnn;;;;
aaaaffffGGGGeeeettttSSSSaaaammmmpppplllleeeeFFFFoooorrrrmmmmaaaatttt((((hhhh,,,, AAAAFFFF____DDDDEEEEFFFFAAAAUUUULLLLTTTT____TTTTRRRRAAAACCCCKKKK,,,, &&&&ssssaaaammmmppppffffmmmmtttt,,,, &&&&ssssaaaammmmppppwwwwiiiiddddtttthhhh))));;;;
////**** ssssaaaammmmppppffffmmmmtttt ccccoooouuuulllldddd oooonnnnllllyyyy bbbbeeee AAAAFFFF____SSSSAAAAMMMMPPPPFFFFMMMMTTTT____TTTTWWWWOOOOSSSSCCCCOOOOMMMMPPPP--------nnnnoooo nnnneeeeeeeedddd ttttoooo cccchhhheeeecccckkkk!!!! ****////
sssswwwwiiiittttcccchhhh ((((ssssaaaammmmppppwwwwiiiiddddtttthhhh))))
{{{{
............ ////**** sssseeeeeeee bbbbeeeelllloooowwww ffffoooorrrr nnnnooootttteeee oooonnnn tttthhhhiiiissss ppppaaaarrrrtttt ****////
- 13 -
}}}}
is incorrect. It is by no means guaranteed that sampfmt is
two's complement. Nor is it guaranteed that sampwidth has
any meaning--the meaning of sampwidth depends on sampfmt.
For example, this version of the Audio File Library can
transfer IEEE floats and IEEE doubles. For these types,
sampwidth has no meaning, and it is ignored and unset. The
code above would behave very unpredictably.
Code should say:
AAAAFFFFffffiiiilllleeeehhhhaaaannnnddddlllleeee hhhh ==== aaaaffffOOOOppppeeeennnnFFFFiiiilllleeee((((................))));;;;
iiiiffff ((((!!!!hhhh)))) rrrreeeettttuuuurrrrnnnn;;;;
aaaaffffGGGGeeeettttSSSSaaaammmmpppplllleeeeFFFFoooorrrrmmmmaaaatttt((((hhhh,,,, AAAAFFFF____DDDDEEEEFFFFAAAAUUUULLLLTTTT____TTTTRRRRAAAACCCCKKKK,,,, &&&&ssssaaaammmmppppffffmmmmtttt,,,, &&&&ssssaaaammmmppppwwwwiiiiddddtttthhhh))));;;;
iiiiffff ((((ssssaaaammmmppppffffmmmmtttt !!!!==== AAAAFFFF____SSSSAAAAMMMMPPPPFFFFMMMMTTTT____TTTTWWWWOOOOSSSSCCCCOOOOMMMMPPPP))))
{{{{
pppprrrriiiinnnnttttffff((((""""TTTThhhhiiiissss pppprrrrooooggggrrrraaaammmm ccccaaaannnn''''tttt rrrreeeeaaaadddd aaaauuuuddddiiiioooo ffffiiiilllleeeessss ooooffff tttthhhhiiiissss """"
ssssaaaammmmpppplllleeee ffffoooorrrrmmmmaaaatttt\\\\nnnn""""))));;;;
eeeexxxxiiiitttt((((0000))));;;;
}}}}
sssswwwwiiiittttcccchhhh ((((ssssaaaammmmppppwwwwiiiiddddtttthhhh)))) ////**** nnnnoooowwww wwwweeee kkkknnnnoooowwww ssssaaaammmmppppwwwwiiiiddddtttthhhh iiiissss mmmmeeeeaaaannnniiiinnnnggggffffuuuullll ****////
{{{{
............ ////**** sssseeeeeeee bbbbeeeelllloooowwww ffffoooorrrr nnnnooootttteeee oooonnnn tttthhhhiiiissss ppppaaaarrrrtttt ****////
}}}}
Another note on sampwidth: even with AIFF files, the sample
width is not necessarily a multiple of 8. Generally, this
can be ignored, because audio samples which do not take up
an integral number of bytes are left-justified inside the
next larger integral number of bytes (with the remaining
bits set to 0). But this may be an issue in code such as
the switch statement above, if it were written:
sssswwwwiiiittttcccchhhh ((((ssssaaaammmmppppwwwwiiiiddddtttthhhh)))) ////**** nnnnoooowwww ssssaaaammmmppppwwwwiiiiddddtttthhhh iiiissss mmmmeeeeaaaannnniiiinnnnggggffffuuuullll ****////
{{{{
ccccaaaasssseeee 8888:::: ddddoooo____8888____tttthhhhiiiinnnngggg(((())));;;; bbbbrrrreeeeaaaakkkk;;;;
ccccaaaasssseeee 11116666:::: ddddoooo____11116666____tttthhhhiiiinnnngggg(((())));;;; bbbbrrrreeeeaaaakkkk;;;;
ccccaaaasssseeee 22224444:::: ddddoooo____22224444____tttthhhhiiiinnnngggg(((())));;;; bbbbrrrreeeeaaaakkkk;;;;
ccccaaaasssseeee 33332222:::: ddddoooo____33332222____tttthhhhiiiinnnngggg(((())));;;; bbbbrrrreeeeaaaakkkk;;;;
ddddeeeeffffaaaauuuulllltttt::::
////**** ffffaaaallllsssseeee aaaassssssssuuuummmmppppttttiiiioooonnnn ****////
pppprrrriiiinnnnttttffff((((""""bbbbaaaadddd rrrreeeettttuuuurrrrnnnn vvvvaaaalllluuuueeee ffffrrrroooommmm AAAAFFFF lllliiiibbbbrrrraaaarrrryyyy!!!!\\\\nnnn""""))));;;;
aaaasssssssseeeerrrrtttt((((0000))));;;;
}}}}
- 14 -
There are two problems here. One is that the code assumes
the maximum size of samples in files opened by the library
is 32 bits, which is definitely not true. The second false
assumption is that the number of bits will be a multiple of
8. Better code would be (after checking that sampfmt is an
integer format):
////**** rrrroooouuuunnnndddd ssssaaaammmmppppwwwwiiiiddddtttthhhh uuuupppp ttttoooo nnnneeeeaaaarrrreeeesssstttt nnnnuuuummmmbbbbeeeerrrr ooooffff bbbbyyyytttteeeessss ****////
iiiinnnntttt nnnnbbbbyyyytttteeeessss ==== (((( ((((ssssaaaammmmppppwwwwiiiiddddtttthhhh----1111)))) //// 8888 )))) ++++ 1111;;;;
sssswwwwiiiittttcccchhhh ((((nnnnbbbbyyyytttteeeessss))))
{{{{
ccccaaaasssseeee 1111:::: ddddoooo____8888____tttthhhhiiiinnnngggg(((())));;;; bbbbrrrreeeeaaaakkkk;;;;
ccccaaaasssseeee 2222:::: ddddoooo____11116666____tttthhhhiiiinnnngggg(((())));;;; bbbbrrrreeeeaaaakkkk;;;;
ccccaaaasssseeee 3333:::: ddddoooo____22224444____tttthhhhiiiinnnngggg(((())));;;; bbbbrrrreeeeaaaakkkk;;;;
ccccaaaasssseeee 4444:::: ddddoooo____33332222____tttthhhhiiiinnnngggg(((())));;;; bbbbrrrreeeeaaaakkkk;;;;
ddddeeeeffffaaaauuuulllltttt::::
pppprrrriiiinnnnttttffff((((""""TTTThhhhiiiissss pppprrrrooooggggrrrraaaammmm ccccaaaannnn''''tttt rrrreeeeaaaadddd aaaauuuuddddiiiioooo ffffiiiilllleeeessss ooooffff tttthhhhiiiissss """"
ssssaaaammmmpppplllleeee wwwwiiiiddddtttthhhh %%%%dddd\\\\nnnn"""",,,, ssssaaaammmmppppwwwwiiiiddddtttthhhh))));;;;
eeeexxxxiiiitttt((((0000))));;;;
}}}}
One final thing about sample widths--don't forget that there
is a special case for reading 24-bit integer data. Because
3-byte data is so difficult to deal with, the library
automatically stretches the data out into convenient 4-byte
quantities in a way compatible with the SGI Audio Library
(AL). The tricky thing here is that the data is sign-
extended on the left for this special case of 17-24-bit
data, whereas the padding that goes on to handle non-
multiple-of-8 sample widths is done by zero-bit-padding on
the right. Here are some examples which should make this
clear, for the case of AF_SAMPFMT_TWOSCOMP:
MMMMSSSSBBBB LLLLSSSSBBBB
bbbbyyyytttteeee 3333 bbbbyyyytttteeee 2222 bbbbyyyytttteeee 1111 bbbbyyyytttteeee 0000
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccccccccccdddddddddddddddddddddddddddddddd |||| SSSSaaaammmmpppplllleeee FFFFoooorrrrmmmmaaaatttt
------------------------------------------------------------------------------------------------------------------------------------++++--------------------------------------------------------------------------------------------------------------------------------
dddddddddddddddddddddddd00000000 |||| 6666----bbbbiiiitttt ddddaaaattttaaaa ttttaaaakkkkeeeessss 8888 bbbbiiiittttssss
RRRRRRRR |||| ((((rrrriiiigggghhhhtttt ppppaaaadddd))))
||||
dddddddddddddddddddddddddddddddd |||| 8888----bbbbiiiitttt ddddaaaattttaaaa ttttaaaakkkkeeeessss 8888 bbbbiiiittttssss
|||| ((((nnnnoooo ppppaaaaddddddddiiiinnnngggg))))
||||
ccccccccccccccccccccccccccccccccdddddddddddddddd0000000000000000 |||| 11112222----bbbbiiiitttt ddddaaaattttaaaa ttttaaaakkkkeeeessss 11116666 bbbbiiiittttssss
RRRRRRRRRRRRRRRR |||| ((((rrrriiiigggghhhhtttt ppppaaaadddd))))
||||
ccccccccccccccccccccccccccccccccdddddddddddddddddddddddddddddddd |||| 11116666----bbbbiiiitttt ddddaaaattttaaaa ttttaaaakkkkeeeessss 11116666 bbbbiiiittttssss
|||| ((((nnnnoooo ppppaaaaddddddddiiiinnnngggg))))
||||
- 15 -
ssss<<<<------------------------bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccccccccccdddddddddddddddd0000000000000000 |||| 22220000----bbbbiiiitttt ddddaaaattttaaaa ttttaaaakkkkeeeessss 33332222 bbbbiiiittttssss
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS RRRRRRRRRRRRRRRR |||| ((((lllleeeefffftttt ssssiiiiggggnnnn----eeeexxxxtttteeeennnndddd AAAANNNNDDDD rrrriiiigggghhhhtttt ppppaaaadddd !!!!))))
||||
ssss<<<<------------------------bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccccccccccdddddddddddddddddddddddddddddddd |||| 22224444----bbbbiiiitttt ddddaaaattttaaaa ttttaaaakkkkeeeessss 33332222 bbbbiiiittttssss
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS |||| ((((lllleeeefffftttt ssssiiiiggggnnnn----eeeexxxxtttteeeennnndddd))))
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccccccccccdddddddddddddddddddddddd00000000 |||| 33330000----bbbbiiiitttt ddddaaaattttaaaa ttttaaaakkkkeeeessss 33332222 bbbbiiiittttssss
RRRRRRRR |||| ((((rrrriiiigggghhhhtttt ppppaaaadddd))))
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccccccccccdddddddddddddddddddddddddddddddd |||| 33332222----bbbbiiiitttt ddddaaaattttaaaa ttttaaaakkkkeeeessss 33332222 bbbbiiiittttssss
|||| ((((nnnnoooo ppppaaaaddddddddiiiinnnngggg))))
||||
Unlike file formats, it doesn't make sense to have a runtime
query of all possible sample formats. The existence of the
new virtual audio format system described above allows
applications to specify in which format they wish to receive
data.
int afGetCompression(AFfilehandle, int);
void afGetCompressionParams(AFfilehandle, int, int *, AUpvlist);
Obviously, new compression methods will be supported, so the
same warnings that apply to afGetSampleFormat apply here.
As the library transparently decompresses input data and
compresses output data, this is not such a big issue. The
application simply must specify the virtual format desired.
A given already-released codec in our library will not
change its native sample format, if we have specified what
that codec's native sample format is. So, for example, if
you know the file is AF_COMPRESSION_G711_ULAW, then you can
assume the native format for that codec is
AF_SAMPFMT_TWOSCOMP, 16 because we said this in a man page.
This is for backwards compatibility. But we do not guarantee
that all future codecs will generate 16-bit signed integer
data natively, nor do we guarantee that all future codecs
will have a single native sample format (some may be
configurable or may vary depending on what kind of data was
originally compressed). In every case though, the
programmer can call afGetSampleFormat to retrieve the sample
format for the current codec on the file corresponding to
the given AFfilehandle.
This new version of the library has a runtime query of all
of the supported compression methods, their textual names,
their compression ratios (if available), and any other info
that may be useful in making a runtime choice of codec.
This is done via afQuery(3dm) in a similar manner to the
file format name string query above.
- 16 -
int afGetChannels(AFfilehandle, int/*track*/);
May return any number of channels, just like it could even
with AIFF and AIFF-C. The virtual number of channels may be
set to any nonzero value.
double afGetRate(AFfilehandle, int/*track*/);
May return any sampling rate, just like it could even with
AIFF and AIFF-C. The current version of the library
provides a transparent conversion mechanism which allows the
programmer to deal with files with unexpected sampling rates
in a simple and clean way via virtual format conversion.
See _a_f_S_e_t_V_i_r_t_u_a_l_R_a_t_e(3dm) for more information.
int afGetTrackIDs(AFfilehandle, int */*track ids*/);
May return more than one track. We give no guarantees that
only one-track formats are supported. An application might
want to reject such a file, or perhaps use the first track.
We do not define the correct behavior.
int afGetMarkIDs(AFfilehandle, int/*track*/, int */*ids*/);
int afGetMarkPosition(AFfilehandle, int/*track*/, int/*markid*/);
char *afGetMarkName(AFfilehandle, int, int);
May return any configuration or number of marks just as it
may with an AIFF/AIFF-C file.
Apps should be written to expect and ignore marks they do
not understand.
int afGetMiscIDs(AFfilehandle, int * /*idlist*/);
int afGetMiscType(AFfilehandle, int /*miscid*/);
int afGetMiscSize(AFfilehandle, int /*miscid*/);
May return ANY type of misc chunk.
Apps should be written to expect and ignore miscellaneous
chunks they do not understand.
Apps should be especially careful not to copy misc chunks
from one file to another unless they understand the content
of those misc chunks; the chunk may contain references to
other parts of the file which the application has modified.
In this case the chunk in the new file becomes corrupt.
This is to be avoided. The chunk should not be copied and
the user should probably be warned.
int afGetAESChannelData(AFfilehandle,int,unsigned char buf[24]);
- 17 -
Will always return data that is to be interpreted as AES
channel data, but there is never any guarantee that such
data will be present or not in a given file format (unless
that file format itself defines AES data as always being
present).
int afGetInstIDs(AFfilehandle, int */*inst ids*/);
long afGetInstParamLong(AFfilehandle, int/*inst*/, int /*param*/);
May return more than one inst, unlike the one fixed INST in
AIFF/AIFF-C files. There are many supported file formats
which have different inst configurations than AIFF/AIFF-C.
The _a_f_Q_u_e_r_y mechanism allows an application to determine in
advance the number of inst chunks supported by a particular
file format. Note that this is the allowable number for
creating a file, not an indication of how many chunks are
present in a file being read. _a_f_G_e_t_I_n_s_t_I_D_s _M_U_S_T be used to
determine the number present in a file opened for read
access prior to loading the values into an array. This is
very important. The following code will dump core when
reading some of the currently supported file formats:
AAAAFFFFffffiiiilllleeeehhhhaaaannnnddddlllleeee hhhh ==== aaaaffffOOOOppppeeeennnnFFFFiiiilllleeee((((................))));;;;
iiiinnnntttt iiiinnnnssssttttIIIIDDDD;;;; ////**** iiiinnnnccccoooorrrrrrrreeeecccctttt aaaassssssssuuuummmmppppttttiiiioooonnnn tttthhhhaaaatttt tttthhhheeeerrrreeee iiiissss oooonnnnllllyyyy oooonnnneeee iiiinnnnsssstttt IIIIDDDD!!!! ****////
iiiiffff ((((!!!!hhhh)))) rrrreeeettttuuuurrrrnnnn;;;;
aaaaffffGGGGeeeettttIIIInnnnssssttttIIIIDDDDssss((((hhhh,,,, AAAAFFFF____DDDDEEEEFFFFAAAAUUUULLLLTTTT____TTTTRRRRAAAACCCCKKKK,,,, &&&&iiiinnnnssssttttIIIIDDDD))));;;; ////**** CCCCOOOORRRREEEE DDDDUUUUMMMMPPPP!!!!!!!! ****////
The correct code should say:
iiiinnnntttt ****iiiinnnnssssttttIIIIDDDDssss ==== NNNNUUUULLLLLLLL;;;; ////**** ffffoooorrrr aaaarrrrrrrraaaayyyy ttttoooo----bbbbeeee----aaaallllllllooooccccaaaatttteeeedddd ****////
iiiinnnntttt nnnnuuuummmmIIIIDDDDSSSS;;;;
AAAAFFFFffffiiiilllleeeehhhhaaaannnnddddlllleeee hhhh ==== aaaaffffOOOOppppeeeennnnFFFFiiiilllleeee((((................))));;;;
iiiiffff ((((!!!!hhhh)))) rrrreeeettttuuuurrrrnnnn;;;;
nnnnuuuummmmIIIIDDDDssss ==== aaaaffffGGGGeeeettttIIIInnnnssssttttIIIIDDDDssss((((hhhh,,,, AAAAFFFF____DDDDEEEEFFFFAAAAUUUULLLLTTTT____TTTTRRRRAAAACCCCKKKK,,,, NNNNUUUULLLLLLLL))));;;; ////**** cccchhhheeeecccckkkk nnnnuuuummmmbbbbeeeerrrr FFFFIIIIRRRRSSSSTTTT ****////
iiiiffff((((nnnnuuuummmmIIIIDDDDssss >>>> 0000)))) {{{{
iiiinnnnssssttttIIIIDDDDssss ==== ((((iiiinnnntttt ****)))) mmmmaaaalllllllloooocccc((((nnnnuuuummmmIIIIDDDDssss **** ssssiiiizzzzeeeeooooffff((((iiiinnnntttt))))))));;;; ////**** aaaallllllllooooccccaaaatttteeee aaaarrrrrrrraaaayyyy ****////
iiiiffff((((!!!!iiiinnnnssssttttIIIIDDDDssss)))) {{{{
eeeerrrrrrrroooorrrr(((())));;;;
rrrreeeettttuuuurrrrnnnn;;;;
}}}}
aaaaffffGGGGeeeettttIIIInnnnssssttttIIIIDDDDssss((((hhhh,,,, AAAAFFFF____DDDDEEEEFFFFAAAAUUUULLLLTTTT____TTTTRRRRAAAACCCCKKKK,,,, iiiinnnnssssttttIIIIDDDDssss))));;;; ////**** nnnnoooowwww llllooooaaaadddd IIIIDDDD aaaarrrrrrrraaaayyyy ****////
////**** ddddoooo wwwwhhhhaaaatttteeeevvvveeeerrrr wwwwiiiitttthhhh iiiinnnnssssttttIIIIDDDDssss ****////
ffffrrrreeeeeeee((((iiiinnnnssssttttIIIIDDDDssss))));;;; ////**** ffffrrrreeeeeeee tttthhhheeee mmmmeeeemmmmoooorrrryyyy ****////
- 18 -
}}}}
Apps should be written to expect and ignore instrument
configurations or instrument parameters they do not
understand.
int afGetLoopIDs(AFfilehandle, int /*inst*/, int*);
int afGetLoopMode(AFfilehandle, int/*inst*/, int /*loopid */);
int afGetLoopStart(AFfilehandle, int/*inst*/, int/*loopid */);
int afGetLoopEnd(AFfilehandle, int/*inst*/, int/*loopid*/);
int afGetLoopTrack(AFfilehandle, int/*inst*/, int/*loopid*/);
May return any configurations of loops within an inst, not
just the fixed value of 2 we have in AIFF/AIFF-C files.
There are many supported file formats which have different
loop configurations than AIFF/AIFF-C.
The _a_f_Q_u_e_r_y mechanism allows an application to determine in
advance the number of loops per inst supported by a
particular file format. _a_f_G_e_t_L_o_o_p_I_D_s _M_U_S_T be used to
determine the number present in a file opened for read
access prior to loading the values into an array. See the
above note for afGetInstIDs for details.
Apps should be written to expect and ignore loop
configurations they do not understand.
9.7.5 _P_R_O_B_L_E_M__2 Some developers are writing bad multi-
threaded code that just happens to work with the AF library.
We have caught several different apps trying to do the
following from multi-threaded code and we imagine that there
are other apps that do this as well:
================================ TTTThhhhrrrreeeeaaaadddd 1111 ========================================================||||============================================ TTTThhhhrrrreeeeaaaadddd 2222 ============================================
|||| |||| ||||
|||| ssssoooommmmeeee aaaammmmoooouuuunnnntttt ooooffff ttttiiiimmmmeeee |||| |||| ssssoooommmmeeee aaaammmmoooouuuunnnntttt ooooffff ttttiiiimmmmeeee
|||| nnnnoooo sssseeeemmmmaaaapppphhhhoooorrrreeee lllloooocccckkkkiiiinnnngggg |||| |||| nnnnoooo sssseeeemmmmaaaapppphhhhoooorrrreeee lllloooocccckkkkiiiinnnngggg
|||| |||| ||||
||||
aaaaffffSSSSeeeeeeeekkkkFFFFrrrraaaammmmeeee((((hhhh,,,,ttttrrrraaaacccckkkk,,,,ppppllllaaaacccceeee1111))));;;; |||| aaaaffffSSSSeeeeeeeekkkkFFFFrrrraaaammmmeeee((((hhhh,,,,ttttrrrraaaacccckkkk,,,,ppppllllaaaacccceeee2222))));;;;
aaaaffffRRRReeeeaaaaddddFFFFrrrraaaammmmeeeessss((((hhhh,,,,ttttrrrraaaacccckkkk,,,,............))));;;; |||| aaaaffffRRRReeeeaaaaddddFFFFrrrraaaammmmeeeessss((((hhhh,,,,ttttrrrraaaacccckkkk,,,,............))));;;;
||||
|||| |||| ||||
|||| ssssoooommmmeeee aaaammmmoooouuuunnnntttt ooooffff ttttiiiimmmmeeee |||| |||| ssssoooommmmeeee aaaammmmoooouuuunnnntttt ooooffff ttttiiiimmmmeeee
|||| nnnnoooo sssseeeemmmmaaaapppphhhhoooorrrreeee lllloooocccckkkkiiiinnnngggg |||| |||| nnnnoooo sssseeeemmmmaaaapppphhhhoooorrrreeee lllloooocccckkkkiiiinnnngggg
|||| |||| ||||
Both threads are making calls on the same AFfilehandle at
the same time, and no concern is put into the order in which
- 19 -
these calls end up being made on the filehandle.
This code is just plain old flat out wrong, it doesn't
matter if you're using the AF or any other library.
It is entirely possible that the order the calls get
executed in by the UNIX scheduler is:
aaaaffffSSSSeeeeeeeekkkkFFFFrrrraaaammmmeeee((((hhhh,,,,ttttrrrraaaacccckkkk,,,,ppppllllaaaacccceeee1111))));;;; ||||
|||| aaaaffffSSSSeeeeeeeekkkkFFFFrrrraaaammmmeeee((((hhhh,,,,ttttrrrraaaacccckkkk,,,,ppppllllaaaacccceeee2222))));;;;
aaaaffffRRRReeeeaaaaddddFFFFrrrraaaammmmeeeessss((((hhhh,,,,ttttrrrraaaacccckkkk,,,,............))));;;; ||||
|||| aaaaffffRRRReeeeaaaaddddFFFFrrrraaaammmmeeeessss((((hhhh,,,,ttttrrrraaaacccckkkk,,,,............))));;;;
in which case both threads would read the wrong data. UNIX
offers absolutely, positively no guarantee that this will
not happen unless the programmer uses one of the many
available process coordination facilities such as
semaphores.
Furthermore, no amount of work on the part of the AF library
writers can prevent this situation, because the library has
no knowledge of what order the programmer really wants the
operations to come in. We cannot use the pid as a hint
because some correctly coded programs may want to seek in
one thread and read in another (correctly coded programs use
locking to make sure that these operations happen in the
right order).
Note that although our example only uses the functions
afSeekFrame() and afReadFrames(), this problem can exist
with calls to ANY Audio File Library functions, even ones
which do not directly manipulate audio files (such as
operations on an AFfilesetup or operations on an
AFfilehandle that query or set parameters stored in memory).
In particular, watch out for uncoordinated calls of
afSyncFile() and afCloseFile(). Making these calls from
more than one thread simultaneously in an uncoordinated
fashion seems to be a common error.
Correct code should look like this:
================================ TTTThhhhrrrreeeeaaaadddd 1111 ========================================================||||============================================ TTTThhhhrrrreeeeaaaadddd 2222 ============================================
||||
|||| |||| ||||
|||| ssssoooommmmeeee aaaammmmoooouuuunnnntttt ooooffff ttttiiiimmmmeeee |||| |||| ssssoooommmmeeee aaaammmmoooouuuunnnntttt ooooffff ttttiiiimmmmeeee
|||| |||| ||||
|||| |||| ||||
||||
LLLLoooocccckkkk SSSSeeeemmmmaaaapppphhhhoooorrrreeee tttthhhhaaaatttt gggguuuuaaaarrrrddddssss hhhh |||| LLLLoooocccckkkk SSSSeeeemmmmaaaapppphhhhoooorrrreeee tttthhhhaaaatttt gggguuuuaaaarrrrddddssss hhhh
- 20 -
aaaaffffSSSSeeeeeeeekkkkFFFFrrrraaaammmmeeee((((hhhh,,,,ttttrrrraaaacccckkkk,,,,ppppllllaaaacccceeee1111))));;;; |||| aaaaffffSSSSeeeeeeeekkkkFFFFrrrraaaammmmeeee((((hhhh,,,,ttttrrrraaaacccckkkk,,,,ppppllllaaaacccceeee2222))));;;;
aaaaffffRRRReeeeaaaaddddFFFFrrrraaaammmmeeeessss((((hhhh,,,,ttttrrrraaaacccckkkk,,,,............))));;;; |||| aaaaffffRRRReeeeaaaaddddFFFFrrrraaaammmmeeeessss((((hhhh,,,,ttttrrrraaaacccckkkk,,,,............))));;;;
UUUUnnnnlllloooocccckkkk SSSSeeeemmmmaaaapppphhhhoooorrrreeee tttthhhhaaaatttt gggguuuuaaaarrrrddddssss hhhh |||| UUUUnnnnlllloooocccckkkk sssseeeemmmmaaaapppphhhhoooorrrreeee tttthhhhaaaatttt gggguuuuaaaarrrrddddssss hhhh
||||
|||| |||| ||||
|||| ssssoooommmmeeee aaaammmmoooouuuunnnntttt ooooffff ttttiiiimmmmeeee |||| |||| ssssoooommmmeeee aaaammmmoooouuuunnnntttt ooooffff ttttiiiimmmmeeee
|||| |||| ||||
|||| |||| ||||
||||
The key thing to realize here is: UNIX guarantees that only
one of the Lock Semaphore calls will succeed immediately.
The thread whose lock does not succeed will sit and wait in
the Lock Semaphore call (and thus not proceed to the
afSeekFrame) until the other thread has unlocked the
semaphore (after doing its seek AND its read). Then when
the other thread unlocks the semaphore, the thread who was
forced to wait will now proceed.
How does one use these semaphores? One uses code such as
the following to create a semaphore FileOpSema with value 1:
####iiiinnnncccclllluuuuddddeeee <<<<uuuulllloooocccckkkkssss....hhhh>>>>
AAAAFFFFffffiiiilllleeeehhhhaaaannnnddddlllleeee hhhh;;;; ////**** gggglllloooobbbbaaaallll ffffiiiilllleeee hhhhaaaannnnddddlllleeee ****////
uuuusssseeeemmmmaaaa____tttt ****FFFFiiiilllleeeeOOOOppppSSSSeeeemmmmaaaa;;;; ////**** gggglllloooobbbbaaaallll sssseeeemmmmaaaapppphhhhoooorrrreeee ttttoooo pppprrrrooootttteeeecccctttt hhhh ****////
////**** iiiinnnniiiittttiiiiaaaalllliiiizzzzeeee sssseeeemmmmaaaapppphhhhoooorrrreeee ssssuuuuppppppppoooorrrrtttt -------- ddddoooo tttthhhhiiiissss oooonnnncccceeee ****////
{{{{
uuuussssppppttttrrrr____tttt ****uuuussssppppttttrrrr;;;;
cccchhhhaaaarrrr ****aaaarrrreeeennnnaaaaffffiiiilllleeee;;;;
////**** uuuusssseeee ffffaaaasssstttteeeesssstttt ((((nnnnoooo ddddeeeebbbbuuuuggggggggiiiinnnngggg)))) ffffoooorrrrmmmm ooooffff sssseeeemmmmaaaapppphhhhoooorrrreeeessss -------- uuuussssccccoooonnnnffffiiiigggg ((((3333PPPP)))) ****////
uuuussssccccoooonnnnffffiiiigggg((((CCCCOOOONNNNFFFF____LLLLOOOOCCCCKKKKTTTTYYYYPPPPEEEE,,,, UUUUSSSS____NNNNOOOODDDDEEEEBBBBUUUUGGGG))));;;;
////**** ccccrrrreeeeaaaatttteeee sssshhhhaaaarrrreeeedddd aaaarrrreeeennnnaaaa ttttoooo hhhhoooolllldddd tttthhhheeee sssseeeemmmmaaaapppphhhhoooorrrreeee -------- uuuussssiiiinnnniiiitttt((((3333PPPP)))) ****////
aaaarrrreeeennnnaaaaffffiiiilllleeee ==== ttttmmmmppppnnnnaaaammmm((((NNNNUUUULLLLLLLL))));;;;
uuuussssppppttttrrrr ==== uuuussssiiiinnnniiiitttt((((aaaarrrreeeennnnaaaaffffiiiilllleeee))));;;;
////****
ccccrrrreeeeaaaatttteeee tttthhhheeee sssseeeemmmmaaaapppphhhhoooorrrreeee iiiinnnn tttthhhhaaaatttt aaaarrrreeeennnnaaaa -------- uuuussssnnnneeeewwwwsssseeeemmmmaaaa((((3333PPPP))))
ccccrrrreeeeaaaatttteeee wwwwiiiitttthhhh ccccoooouuuunnnntttt 1111--------tttthhhheeeerrrreeee iiiissss 1111 rrrreeeessssoooouuuurrrrcccceeee ((((hhhh)))),,,, wwwwhhhhiiiicccchhhh iiiissss
iiiinnnniiiittttiiiiaaaallllllllyyyy aaaavvvvaaaaiiiillllaaaabbbblllleeee....
****////
FFFFiiiilllleeeeOOOOppppSSSSeeeemmmmaaaa ==== uuuussssnnnneeeewwwwsssseeeemmmmaaaa((((uuuussssppppttttrrrr,,,,1111))));;;;
////**** wwwweeee wwwwoooonnnn''''tttt nnnneeeeeeeedddd ttttoooo rrrreeeeffffeeeerrrr ttttoooo aaaarrrreeeennnnaaaa aaaaggggaaaaiiiinnnn ssssoooo wwwweeee ccccaaaannnn uuuunnnnlllliiiinnnnkkkk ffffiiiilllleeee ****////
uuuunnnnlllliiiinnnnkkkk((((aaaarrrreeeennnnaaaaffffiiiilllleeee))));;;;
}}}}
- 21 -
Then one uses uspsema(3P) to lock the semaphore, and
usvsema(3P) to unlock the semaphore. Pretty simple:
================================ TTTThhhhrrrreeeeaaaadddd 1111 ========================================================||||============================================ TTTThhhhrrrreeeeaaaadddd 2222 ============================================
||||
|||| |||| ||||
|||| ssssoooommmmeeee aaaammmmoooouuuunnnntttt ooooffff ttttiiiimmmmeeee |||| |||| ssssoooommmmeeee aaaammmmoooouuuunnnntttt ooooffff ttttiiiimmmmeeee
|||| |||| ||||
|||| |||| ||||
||||
uuuussssppppsssseeeemmmmaaaa((((FFFFiiiilllleeeeOOOOppppSSSSeeeemmmmaaaa))));;;; ////****lllloooocccckkkk****//// |||| uuuussssppppsssseeeemmmmaaaa((((FFFFiiiilllleeeeOOOOppppSSSSeeeemmmmaaaa))));;;; ////****lllloooocccckkkk****////
aaaaffffSSSSeeeeeeeekkkkFFFFrrrraaaammmmeeee((((hhhh,,,,ttttrrrraaaacccckkkk,,,,ppppllllaaaacccceeee1111))));;;; |||| aaaaffffSSSSeeeeeeeekkkkFFFFrrrraaaammmmeeee((((hhhh,,,,ttttrrrraaaacccckkkk,,,,ppppllllaaaacccceeee2222))));;;;
aaaaffffRRRReeeeaaaaddddFFFFrrrraaaammmmeeeessss((((hhhh,,,,ttttrrrraaaacccckkkk,,,,............))));;;; |||| aaaaffffRRRReeeeaaaaddddFFFFrrrraaaammmmeeeessss((((hhhh,,,,ttttrrrraaaacccckkkk,,,,............))));;;;
uuuussssvvvvsssseeeemmmmaaaa((((FFFFiiiilllleeeeOOOOppppSSSSeeeemmmmaaaa))));;;; ////****uuuunnnnlllloooocccckkkk****//// |||| uuuussssvvvvsssseeeemmmmaaaa((((FFFFiiiilllleeeeOOOOppppSSSSeeeemmmmaaaa))));;;; ////****uuuunnnnlllloooocccckkkk****////
||||
|||| |||| ||||
|||| ssssoooommmmeeee aaaammmmoooouuuunnnntttt ooooffff ttttiiiimmmmeeee |||| |||| ssssoooommmmeeee aaaammmmoooouuuunnnntttt ooooffff ttttiiiimmmmeeee
|||| |||| ||||
|||| |||| ||||
||||
Now, why are we pointing this out for AF users?
We have found several applications which were actually
committing this error and were GETTING AWAY WITH IT! By the
most arcane of coincidences of CPU scheduler timings, these
apps just happened to never fall into the short window of
time in which the above worst-case scenario could occur.
When these programs were recompiled with an alpha version of
a newer Audio File Library, which contains different code
and thus has slightly different timing characteristics and
gets scheduled slightly differently, the bug in these
applications was instantly revealed.
This is why we want to alert developers to check their code
for this-- there could be a bug of this type in their code
which had previously not come out, just because the old AF
happens to have had this property (by no design of our own).
We want to give developers plenty of advanced warning about
this situation.
9.7.6 _P_R_O_B_L_E_M__3 Some developers are writing multi-threaded
code that would be good under their assumption that the AF
is MT/MP-safe. But this assumption is false.
The AF is NOT a multi-thread and/or multi-processor safe
library, in the following sense:
- 22 -
Users can make multiple, simultaneous, uncoordinated AF
calls on different AFfilehandles from different threads and
the library will operate fine. Each AFfilehandle completely
encapsulates the state needed to do operations on that
AFfilehandle (except for error handling, which is explained
next).
Users cannot make multiple, simultaneous, uncoordinated AF
calls from different threads to set or access the library's
global state--namely, the error handler function. If two
threads simultaneously try and set the error handler (even
the same error handler), the behavior is undefined.
Furthermore, if the user writes an error handler, then makes
multiple, simultaneous, uncoordinated AF calls on different
filehandles from different threads, and both AF calls issue
an error simultaneously, then two instances of the user's
error handler will be called in a simultaneous,
uncoordinated manner in two threads. If this situation is
possible in a user's program, the user should use semaphores
in their error handler in order to make sure their handler
doesn't try and report or deal with two errors at the same
time. Note that any AF function can cause an AF error to
occur. Do not assume a function will not err just because
it is simple.
A thread-safe error handling routine is now available via
the Digital Media Library. Any application which is
expected to function in a multi-threaded fashion should
disable the old global _A_F_e_r_r_o_r_h_a_n_d_l_e_r and use
_d_m_G_e_t_E_r_r_o_r(3dm) in its place. Here is a simple example:
####iiiinnnncccclllluuuuddddeeee <<<<ssssttttddddiiiioooo....hhhh>>>>
####iiiinnnncccclllluuuuddddeeee <<<<ddddmmmmeeeeddddiiiiaaaa////ddddmmmmeeeeddddiiiiaaaa....hhhh>>>>
####iiiinnnncccclllluuuuddddeeee <<<<ddddmmmmeeeeddddiiiiaaaa////aaaauuuuddddiiiiooooffffiiiilllleeee....hhhh>>>>
////**** tttthhhhiiiissss rrrroooouuuuttttiiiinnnneeee aaaassssssssuuuummmmeeeessss ffffiiiilllleeee hhhhaaaannnnddddlllleeee iiiissss ooooppppeeeennnn,,,, aaaannnndddd bbbbuuuuffffffffeeeerrrr iiiissss aaaallllllllooooccccaaaatttteeeedddd ****////
////**** rrrreeeettttuuuurrrrnnnnssss nnnnuuuummmmbbbbeeeerrrr ooooffff ffffrrrraaaammmmeeeessss aaaaccccttttuuuuaaaallllllllyyyy rrrreeeeaaaadddd,,,, oooorrrr ----1111 oooonnnn eeeerrrrrrrroooorrrr ****////
iiiinnnntttt rrrreeeeaaaaddddBBBBuuuuffffffffeeeerrrr((((AAAAFFFFffffiiiilllleeeehhhhaaaannnnddddlllleeee hhhh,,,, vvvvooooiiiidddd ****bbbbuuuuffffffffeeeerrrr,,,, iiiinnnntttt ffffrrrraaaammmmeeeessss))))
{{{{
iiiinnnntttt ffffrrrraaaammmmeeeessssRRRReeeeaaaadddd ==== aaaaffffRRRReeeeaaaaddddFFFFrrrraaaammmmeeeessss((((hhhh,,,, AAAAFFFF____DDDDEEEEFFFFAAAAUUUULLLLTTTT____TTTTRRRRAAAACCCCKKKK,,,, bbbbuuuuffffffffeeeerrrr,,,, ffffrrrraaaammmmeeeessss))));;;;
iiiiffff((((ffffrrrraaaammmmeeeessssRRRReeeeaaaadddd <<<< 0000)))) {{{{ ////**** eeeerrrrrrrroooorrrr!!!! ****////
ffffpppprrrriiiinnnnttttffff((((ssssttttddddeeeerrrrrrrr,,,, """"FFFFaaaattttaaaallll eeeerrrrrrrroooorrrr:::: %%%%ssss\\\\nnnn"""",,,, ddddmmmmGGGGeeeettttEEEErrrrrrrroooorrrr((((NNNNUUUULLLLLLLL,,,, NNNNUUUULLLLLLLL))))))));;;;
rrrreeeettttuuuurrrrnnnn ----1111;;;;
}}}}
rrrreeeettttuuuurrrrnnnn ffffrrrraaaammmmeeeessssRRRReeeeaaaadddd;;;;
}}}}
Then elsewhere, prior to this call, you would have:
- 23 -
aaaaffffSSSSeeeettttEEEErrrrrrrroooorrrrHHHHaaaannnnddddlllleeeerrrr((((NNNNUUUULLLLLLLL))));;;; ////**** ddddiiiissssaaaabbbblllleeee oooolllldddd----ssssttttyyyylllleeee gggglllloooobbbbaaaallll eeeerrrrrrrroooorrrr hhhhaaaannnnddddlllleeeerrrr ****////
Now the most important caveat: users cannot make multiple,
simultaneous, uncoordinated AF calls on the SAME
AFfilehandle from different threads, even if the order of
execution of those calls does not matter to the user. Doing
so will very likely cause a core dump, or at least
corruption of the AFfilehandle. This behavior will never be
changed, as we refuse to make our developers pay the price
of semaphore locking code at the beginning and end of every
afReadFrames and afWriteFrames call. Most users do not
need, and in fact really do not want, semaphore protection
that is built-in to the AF calls themselves.
Like problem 2, problem 3 can occur with any AF call, not
just afSeekFrame() and afReadFrames(). In particular, watch
out for simultaneous calls of afSyncFile() and
afCloseFile().
Note that at no point did we offer any guarantee that the
library was MT/MP-safe, and in fact only libraries specified
as such in man pages (such as the C library minus errno, as
explained in intro(3)) are guaranteed to be so.
9.7.7 _P_R_O_B_L_E_M__4 Some developers are using afOpenFD() or
afGetFD() to get the file descriptor which an AFfilehandle
is using, and then changing the file pointer on that file
descriptor. The AF does not allow this.
The file descriptor returned by afGetFD() was intended to be
used as part of a select() loop and was not intended to
allow users to read, write, and seek in the file without the
knowledge of the Audio File Library. Doing so will cause
the library to give unpredictable results unless the user
saves and restores the file position whenever they modify
it.
The reason for this is that we are not willing to force upon
users expecting high performance the often very large
overhead of an lseek(2) system call on every afReadFrames()
or afWriteFrames(). Therefore we cannot restore the file
position to a known place on every AF call which relies on
the file being in that place.
Users who wish to modify the file position of the file
descriptor given by afGetFD() should save the file position
and restore it after they are finished and before they make
the next AF call to read or write data to the file. The new
routines _a_f_S_a_v_e_F_i_l_e_P_o_s_i_t_i_o_n(3dm) and
_a_f_R_e_s_t_o_r_e_F_i_l_e_P_o_s_i_t_i_o_n(3dm) have been created expressly for
this purpose. Alternately they can use one of two different
- 24 -
file descriptors opened to the same file (dup(2) will not
work; it gives you two file descriptors which share a file
offset. The file must be re-opened in order to get a
separate file descriptor). Also, if users attempt to write
to the file, no matter how the AFfilehandle was opened, the
results are undefined.
Developers had asked for a call to get the offset of the
audio data in an audio file. Two new functions have been
made available. afGetDataOffset(3dm) returns the offset in
bytes from the beginning of an open audio file to the first
audio sample. afGetTrackBytes(3dm) returns the size in
bytes of the audio data portion of a given track in an audio
file.
9.7.8 _W_A_R_N_I_N_G We give no guarantees about the number or
nature of UNIX system calls that will result from a given AF
call. In particular, afReadFrames() and afWriteFrames()
could actually read() or write() any amount of data in the
file, or could read() or write() more than once in varying
chunk sizes. Also, afOpenFile(), afSeekFrame(),
afSyncFile(), afCloseFile(), and other AF functions could
result in any amount of data being read from or written to
the file. (but of course the AF will not write to a file
opened for read access or read from a file opened for write
access).
Users who are attempting to optimize the I/O in their
program by managing I/O system call behavior should be aware
that at this time we offer no guarantees about when the AF
will perform system calls.
This has not been a problem to our knowledge, but we thought
it would be a good idea just to make this explicit. At this
time we offer no guarantees that a read of, say, 50,000
frames will result in a single UNIX read() system call for
exactly 50,000 frames worth of data. Although we will
strive to make this the case whenever it seems beneficial,
there are certain cases where this is simply impossible.
For example, reads from or writes to a compressed file will
generally be split up into a chunksize which is natural for
the codec being used, and thus possibly result in several
reads or writes to the file. Also, we give no guarantee
that afSeekFrame() will seek the file at all in the UNIX
lseek() sense, although it happens that this is generally
the case for the current Audio File Library. And even if
afSeekFrame() does lseek() the file, we do not guarantee
that it will be to the exact frame the user specified
(though this is generally the case in the old AF library).
This is due to necessary compensation for filter delays
inherent in certain forms of compression and decompression.
- 25 -
In a future release, features will be introduced which may
make this more of an issue. At that time we will come up
with much more specific information about what guarantees we
can offer to the developer. We want to find out if these
kinds of guarantees are something that developers need at
all. Perhaps it is simply not an issue for developers. But
if it is, we would be most interested in hearing your
feedback. You can contact your local SGI representative and
ask them to send a message to the developers of the Audio
File Library, or you can also use the newsgroup
comp.sys.sgi.audio for faster and much more direct contact.